package sys_serv

import (
	"strconv"
	"strings"
	"ubt-aio-service/app/mod/sys_mod"
	"ubt-aio-service/app/pkg/db"
	"ubt-aio-service/app/utils"
)

type sysDict struct{}

var SysDictServ = sysDict{}

// Add 新增分类或数据
func (s *sysDict) Add(req *sys_mod.SysDictSaveReq) *utils.ResJson {
	sqlStr := "INSERT INTO sys_dict(dict_name, quan_pin, jian_pin, short_name, full_name, dict_code, kind, type_id, type_code, parent_id, sort, logo_id, logo_name, logo_url, remarks, states, opt_user, opt_dept, add_time, upd_time) " +
		"VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, 1, $16, $17, EXTRACT(epoch FROM NOW()), EXTRACT(epoch FROM NOW()))"
	return db.CudData(sqlStr, req.DictName, req.QuanPin, req.JianPin, req.ShortName, req.FullName, req.DictCode, req.Kind,
		req.TypeId, req.TypeCode, req.ParentId, req.Sort, req.LogoId, req.LogoName, req.LogoUrl, req.Remarks, req.OptUser, req.OptDept)
}

// Exists 判断平台编码是否存在
func (s *sysDict) Exists(req *sys_mod.SysDictExtVo) bool {
	sqlStr := "SELECT dict_id FROM sys_dict WHERE states=1 AND kind=$1 AND type_id=$2 AND parent_id=$3 AND dict_code=$4"
	param := make([]any, 0)
	param = append(param, req.Kind)
	param = append(param, req.TypeId)
	param = append(param, req.ParentId)
	param = append(param, req.DictCode)
	if req.DictId != "" {
		sqlStr += " AND dict_id!=$5"
		param = append(param, req.DictId)
	}
	if res := db.GetOne(sqlStr, param...); res.Code == utils.Succeed.Code {
		return true
	}
	return false
}

// Update 修改数据
func (s *sysDict) Update(req *sys_mod.SysDictSaveReq) *utils.ResJson {
	sqlStr := "UPDATE sys_dict SET dict_name=$1, quan_pin=$2, jian_pin=$3, short_name=$4, full_name=$5, dict_code=$6, kind=$7, type_id=$8, type_code=$9, parent_id=$10, sort=$11, logo_id=$12, logo_name=$13, logo_url=$14, remarks=$15, upd_time=EXTRACT(epoch FROM NOW()) WHERE dict_id=$16"
	return db.CudData(sqlStr, req.DictName, req.QuanPin, req.JianPin, req.ShortName, req.FullName, req.DictCode,
		req.Kind, req.TypeId, req.TypeCode, req.ParentId, req.Sort, req.LogoId, req.LogoName, req.LogoUrl, req.Remarks, req.DictId)
}

// UpdTypeCode 修改数据字典的分类编码
func (s *sysDict) UpdTypeCode(ch chan int, req *sys_mod.SysDictTypeReq) {
	sqlStr := "UPDATE sys_dict SET type_code=$1 WHERE kind=2 AND type_id=$2"
	db.CudData(sqlStr, req.TypeCode, req.TypeId)
	<-ch
}

// Deletes 删除数据
func (s *sysDict) Deletes(req *sys_mod.SysDictProReq) *utils.ResJson {
	var (
		param  []any
		idList []string
		q      string
		n      = 0
	)
	idArr := strings.Split(req.DictIds, ",")
	res := s.selDicts(req.Kind)
	for _, curId := range idArr {
		idList = append(idList, curId)
		if res.Code == utils.Succeed.Code {
			idList = s.getIds(res.Data.([]map[string]any), curId, idList)
		}
	}
	for _, curId := range idList {
		n++
		q += "$" + strconv.Itoa(n) + ","
		param = append(param, curId)
	}
	q = q[:len(q)-1]
	sqlStr := "UPDATE sys_dict SET states=2, upd_time=EXTRACT(epoch FROM NOW()) WHERE dict_id IN (" + q + ")"
	return db.CudData(sqlStr, param...)
}

// DelByType 根据分类编码删除数据
func (s *sysDict) DelByType(ch chan int, typeIds string) {
	var (
		kind   uint8 = 2
		param  []any
		idList []string
		q      string
		n      = 0
	)
	idArr := strings.Split(typeIds, ",")
	res := s.selDicts(kind)
	for _, curId := range idArr {
		idList = append(idList, curId)
		if res.Code == utils.Succeed.Code {
			idList = s.getIds(res.Data.([]map[string]any), curId, idList)
		}
	}
	for _, curId := range idList {
		n++
		q += "$" + strconv.Itoa(n) + ","
		param = append(param, curId)
	}
	q = q[:len(q)-1]
	sqlStr := "UPDATE sys_dict SET states=2, upd_time=EXTRACT(epoch FROM NOW()) WHERE type_id IN (" + q + ")"
	db.CudData(sqlStr, param...)
	<-ch
}

// selDicts 获取所有数据的编号
func (s *sysDict) selDicts(kind uint8) *utils.ResJson {
	return db.GetAll("SELECT dict_id, parent_id FROM sys_dict WHERE states=1 AND kind=$1 ORDER BY sort", kind)
}

// getIds 遍历获取子级数据编号
func (s *sysDict) getIds(list []map[string]any, id any, newList []string) []string {
	for _, item := range list {
		if id == item["parentId"] {
			newList = append(newList, item["dictId"].(string))
			newList = s.getIds(list, item["dictId"], newList)
		}
	}
	return newList
}

// One 获取数据详情
func (s *sysDict) One(dictId string) *utils.ResJson {
	sqlStr := `SELECT a.dict_id, a.dict_name, a.short_name, a.full_name, a.dict_code, a.kind, a.type_code, a.parent_id, 
		(CASE WHEN a.parent_id='111111111111111111111' THEN '一级分类' ELSE b.dict_name END) parent_name, 
		(CASE WHEN a.parent_id='111111111111111111111' THEN '1000' ELSE b.dict_code END) parent_code, a.sort, 
		a.logo_id, a.logo_name, a.logo_url, a.remarks, a.opt_user, a.add_time, a.upd_time 
		FROM sys_dict a 
		LEFT JOIN sys_dict b ON b.states=1 AND a.kind=b.kind AND a.type_id=b.type_id AND a.parent_id=b.dict_id 
		WHERE a.dict_id=$1`
	return db.GetOne(sqlStr, dictId)
}

// List 获取数据树状列表
func (s *sysDict) List(req *sys_mod.SysDictListReq) *utils.ResJson {
	var (
		sqlStr string
		res    *utils.ResJson
	)
	if req.Kind == 1 {
		// 查询分类
		sqlStr = "SELECT a.dict_id, a.dict_name, a.short_name, a.dict_code, a.type_code, '' AS type_name, " +
			"a.parent_id, a.sort, a.add_time, COUNT(b.dict_id) AS nums " +
			"FROM sys_dict a LEFT JOIN sys_dict b ON b.states=1 AND b.kind=2 AND a.dict_id=b.type_id " +
			"WHERE a.states=1 AND a.kind=1 " +
			"GROUP BY a.dict_id, a.dict_name, a.short_name, a.dict_code, a.type_code, a.parent_id, a.sort, a.add_time " +
			"ORDER BY sort"
		res = db.GetAll(sqlStr)
	} else {
		// 查询数据
		sqlStr = "SELECT a.dict_id, a.dict_name, a.short_name, a.dict_code, a.type_code, b.dict_name AS type_name, " +
			"a.parent_id, a.sort, a.add_time, 0 nums " +
			"FROM sys_dict a LEFT JOIN sys_dict b ON b.states=1 AND b.kind=1 AND a.type_id=b.dict_id " +
			"WHERE a.states=1 AND a.kind=2 AND a.type_code=$1 " +
			"ORDER BY sort"
		res = db.GetAll(sqlStr, req.TypeCode)
	}
	if res.Code == utils.Succeed.Code {
		var newList []map[string]any
		var level uint8 = 1
		for _, item := range res.Data.([]map[string]any) {
			if item["parentId"] == "111111111111111111111" {
				item["level"] = level
				newList = append(newList, item)
				newList = s.sortChildDict(res.Data.([]map[string]any), item["dictId"], newList, level)
			}
		}
		return &utils.ResJson{Code: utils.Succeed.Code, Msg: utils.Succeed.Msg, Data: newList}
	}
	return utils.NoData
}

// sortChildDict 将数据按树状排序
func (s *sysDict) sortChildDict(list []map[string]any, id any, newList []map[string]any, level uint8) []map[string]any {
	level++
	for _, item := range list {
		if id == item["parentId"] {
			item["level"] = level
			newList = append(newList, item)
			newList = s.sortChildDict(list, item["dictId"], newList, level)
		}
	}
	return newList
}

// Sort 获取数据数量，用于排序
func (s *sysDict) Sort(req *sys_mod.SysDictSortReq) *utils.ResJson {
	var res *utils.ResJson
	sqlStr := "SELECT COUNT(1)+1 AS nums FROM sys_dict WHERE states=1 "
	if req.Kind == 1 {
		sqlStr += "AND kind=1 AND parent_id=$1"
		res = db.GetOne(sqlStr, req.ParentId)
	} else {
		sqlStr += "AND kind=2 AND type_code=$1 AND parent_id=$2"
		res = db.GetOne(sqlStr, req.TypeId, req.ParentId)
	}
	return &utils.ResJson{Code: utils.Succeed.Code, Msg: utils.Succeed.Msg, Data: res.Data.(map[string]any)["nums"].(int64)}
}

// Tree 获取数据树状列表
func (s *sysDict) Tree(req *sys_mod.SysDictListReq) *utils.ResJson {
	var (
		sqlStr string
		res    *utils.ResJson
	)
	if req.Kind == 1 {
		sqlStr = "SELECT dict_id sel_id, dict_name sel_name, dict_code sel_code, parent_id " +
			"FROM sys_dict WHERE states=1 AND kind=1 " +
			"ORDER BY sort"
		res = db.GetAll(sqlStr)
	} else {
		sqlStr = "SELECT dict_id sel_id, dict_name sel_name, dict_code sel_code, parent_id " +
			"FROM sys_dict WHERE states=1 AND kind=2 AND type_code=$1 " +
			"ORDER BY sort"
		res = db.GetAll(sqlStr, req.TypeCode)
	}
	if res.Code == utils.Succeed.Code {
		var level uint8 = 0
		tree := s.buildTree("111111111111111111111", res.Data.([]map[string]any), level)
		return &utils.ResJson{Code: utils.Succeed.Code, Msg: utils.Succeed.Msg, Data: tree}
	}
	return utils.NoData
}

// buildTree 创建数据的树状列表
func (s *sysDict) buildTree(parentId any, list []map[string]any, level uint8) []map[string]any {
	tree := make([]map[string]any, 0)
	level++
	for _, child := range list {
		if parentId == child["parentId"] {
			children := s.buildTree(child["selId"], list, level)
			child["level"] = level
			child["children"] = children
			tree = append(tree, child)
		}
	}
	return tree
}

// Select 选择数据
func (s *sysDict) Select(req *sys_mod.SysDictSelReq) *utils.ResJson {
	var (
		param []any
		n     = 0
	)
	sqlStr := "SELECT dict_id sel_id, dict_name sel_name, dict_code sel_code, parent_id " +
		"FROM sys_dict WHERE states=1 AND kind=2 AND type_code=$1 "
	if req.Keywords != "" {
		sqlStr += " AND ("
		nameArr := strings.Split(req.Keywords, " ")
		for _, name := range nameArr {
			sqlStr += "dict_name LIKE '%'||$" + strconv.Itoa(n+1) + "||'%' OR " +
				"dict_code LIKE '%'||$" + strconv.Itoa(n+2) + "||'%' OR "
			param = append(param, name)
			param = append(param, name)
			n += 2
		}
		sqlStr = sqlStr[:len(sqlStr)-4]
		sqlStr += ")"
	}
	sqlStr += "ORDER BY sort"
	res := db.GetAll(sqlStr, req.TypeCode)
	if res.Code == utils.Succeed.Code {
		var level uint8 = 0
		tree := s.buildTree("111111111111111111111", res.Data.([]map[string]any), level)
		return &utils.ResJson{Code: utils.Succeed.Code, Msg: utils.Succeed.Msg, Data: tree}
	}
	return utils.NoData
}

// SelDepts 获取部门及用户数量数据树状列表
func (s *sysDict) SelDepts(typeCode string) *utils.ResJson {
	sqlStr := "SELECT a.dict_id, a.dict_name, a.dict_code, a.parent_id, a.sort, COUNT(b.user_id) nums " +
		"FROM sys_dict a LEFT JOIN sys_user b ON b.states=1 AND a.dict_id=b.dept_id " +
		"WHERE a.states=1 AND a.kind=2 AND type_code=$1 " +
		"GROUP BY a.dict_id, a.dict_name, a.dict_code, a.parent_id, a.sort ORDER BY a.sort"
	if res := db.GetAll(sqlStr, typeCode); res.Code == utils.Succeed.Code {
		var newList []map[string]any
		var level uint8 = 1
		for _, item := range res.Data.([]map[string]any) {
			if item["parentId"] == "111111111111111111111" {
				item["level"] = level
				newList = append(newList, item)
				newList = s.sortChildDict(res.Data.([]map[string]any), item["dictId"], newList, level)
			}
		}
		return &utils.ResJson{Code: utils.Succeed.Code, Msg: utils.Succeed.Msg, Data: newList}
	}
	return utils.NoData
}
